<?php
/**
 *
 * @author 刘贻章
 * @package Core.DB 数据库类(根据配置选择具体的数据库：mysql 或者 mongodb)
 * @version 1.0 beat
 * @copyright 2010-11-02
 */

class DbAgent { 
	//配置信息
	private static $dns = array();
	//单例
	private static $instance = array();
	//获得当前配置信息
	public $config = array();
	//mc连接
	private $conn;
	//选择的数据
	private $db;
	//存放库操作后返回的资源句柄	
	private $_tmpRes = null;

	private function __construct($name){
		//获取配置信息 
		if(!self::$dns){
			$conf = CONFIG_DIR . DIRECTORY_SEPARATOR ."db.php";
			if(!file_exists($conf)) die("配置文件db.php不存在");
			self::$dns = include($conf);
		}	
		$this->config = self::$dns[$name];
		if(!is_array($this->config)){
			die("db.php没有{$name}配置项目");
		}
		
		if ($this->config['db'] == "mysql")
			{
			$this->conn = mysql_connect($this->config['mysql_host'].":".$this->config['mysql_port'],$this->config['mysql_user'],$this->config['mysql_pwd']);
			mysql_select_db($this->config['mysql_db'],$this->conn) or die(mysql_error());
			mysql_query("set names utf8");
			}
		else if ($this->config['db'] == "mongodb")
			{
			$link = "mongodb://";
			if ($this->config["mongodb_user"]) {
				$link .= $this->config["mongodb_user"] . ":" . $this->config["mongodb_pwd"] . "@";
			}
			$link .= $this->config["mongodb_host"] . ":" . $this->config["mongodb_port"];
			try {
				$this->conn = new Mongo($link);
				$m_db = $this->config["mongodb_db"];
				$this->db = $this->conn->$m_db;
				} catch (MongoConnectionException $e) {
					echo ("can_not_connect". $e->getMessage());
					exit();
				}			
			}
	}
	
	/**
	 * 单例模式
	 * @param $name
	 */
	public static function getInstance($name="main"){
		if(empty(self::$instance[$name])) {
			self::$instance[$name] = new self($name);
		}
		return self::$instance[$name];
	}
		
	/**
	 * 获取连接
	 */
	public function getConn(){
		return $this->conn;
	}

	/**
	 * 获取数据库
	 */
	public function getDb(){
		return $this->db;
	}
		
	/**
	 * 执行指令
	 *
	 * @param string $sql
	 * @package string $dsn
	 */
	public function query($sql){
		$result = mysql_query($sql,$this->conn);
		if(!$result) die("SQL:{$sql} ".mysql_error());
		$this->_tmpRes = $result;
	}
	
	/**
	 * 取一条记录
	 *
	 * @param string $sql
	 * @param string $cacheId
	 * @return array
	 */
	public function fetchOne($sql){
		$this->query($sql);
		return mysql_fetch_assoc($this->_tmpRes);
	}
	
	/**
	 * 最后插入的ID
	 *
	 * @param string $sql
	 * @return array
	 */
	public function getLastInsertId(){
		return mysql_insert_id($this->conn);
	}
	
	/**
	 * 取记录 并根据自动hash结果集
	 *
	 * @param string $sql
	 * @param string $dsn 指定数据库，对于数据库配置的mark
	 * @param string $hashBy
	 * @return array
	 */
	public function fetchRow($sql,$hashBy=null){
		$return = array();
		$this->query($sql);
		if(!$hashBy){
			while ($res = mysql_fetch_assoc($this->_tmpRes)) {
				$return[] = $res;
			}
		}else{
			while ($res = mysql_fetch_assoc($this->_tmpRes)) {
				$return[$res[$hashBy]] = $res;
			}
		}
		return $return;
	}
	
	public function getRes(){
		return $this->_tmpRes;
	}
	
	/**
	 * 影响记录数
	 *
	 * @param string $sql
	 * @return array
	 */
	public function getAffectRows(){
		return mysql_affected_rows($this->conn);
	}
	
	public function getNumRows() {
		return mysql_num_rows($this->_tmpRes);
	}
	
	
	/**
	 * 取记录, 返回结果集
	 *
	 * @param string $collection	collection
	 * @param array $wheres 		条件        例：array("x" => array('$gt' => 80))
	 * @param array $fields 		指定域(null为所有)
	 * @param array $orderby		排序
	 * @return array
	 * 
     * Less than.							const LT = '$lt';
     * Less than or equal to.				const LTE = '$lte';
     * Greater than.						const GT = '$gt';
     * Greater than or equal to.    		const GTE = '$gte';
     * Checks for a field in an object.	    const IN = '$in';
     * Not equal.						    const NE = '$ne';
     * Sort ascending.					    const ASC = 1;
     * Sort descending.						const DESC = -1;
	 */
	public function fetchRow_mongodb($collection, $wheres, $fields, $orderby, $limit = null, $returnId=false) {
		$ret = array();
		$collection = $this->db->$collection;		
		if ( ! $wheres ) 
		{
			$wheres = array();
		}		
		if ( ! $fields )
		{
			$fields = array();
		}
        //可返回_id
        if(!$returnId)
		    $fields["_id"] = 0;

		try {
			$rs = $collection->find($wheres, $fields);
//            if($_REQUEST['a'])
//            {
//                debug_print_backtrace();
//            }
            if ( $orderby )
            {
                $rs = $rs->sort((object)$orderby);
            }
			if ( $limit )
			{
				$rs = $rs->limit($limit);
			}
//            if($_REQUEST['a'])
//            {
//                while( $rs->hasNext() ) {
//                    var_dump( $rs->getNext() );
//                }
//            }
			foreach ( $rs as $k =>$r )
			{
				$ret[] = $r;
			}
		} catch (Exception $e) {}			
		return $ret;
	}		

	/**
	 * 取一条记录
	 *
	 * @param string $collection	collection
	 * @param array $wheres 		条件        例：array("x" => array('$gt' => 80))
	 * @param array $fields 		指定域(null为所有)
	 * @param array $orderby		排序
	 * @return array
	 * 
     * Less than.							const LT = '$lt';
     * Less than or equal to.				const LTE = '$lte';
     * Greater than.						const GT = '$gt';
     * Greater than or equal to.    		const GTE = '$gte';
     * Checks for a field in an object.	    const IN = '$in';
     * Not equal.						    const NE = '$ne';
     * Sort ascending.					    const ASC = 1;
     * Sort descending.						const DESC = -1;
	 */
	public function fetchOne_mongodb($collection, $wheres, $fields, $orderby, $returnId=false){
		$return = array();
		$collection = $this->db->$collection;
		
		if ($wheres == null) $wheres_1 = array();
		else $wheres_1 = $wheres;
			
		if ($fields == null) $fields_1 = array();
		else $fields_1 = $fields;
        if(!$returnId)
		    $fields_1["_id"] = 0;
		try {
			if ($orderby == null)
				$result = $collection->find($wheres_1, $fields_1)->limit(1); 
			else
				$result = $collection->find($wheres_1, $fields_1)->sort((object)$orderby)->limit(1); 
			$ret = array();
			foreach($result as $val){ $ret[] = $val;};
			$return = empty($ret) ? array() : $ret[0];
		} catch (Exception $e) {
				$return = "error";
		}			
		return $return;
	}	

	/**
	 * 获取一个自增字段值
	 *
	 * @param string $table_name			表名
	 * @param string $auto_increment		自增字段			例："id"
	 * @return array
	 */
	public function getAutoId_mongodb($table_name, $auto_increment)
	{
		try {
			$update = array("$"."inc"=>array("$auto_increment"=>1));
			$query = array("name"=>"$table_name");
			$command = array(
					"findandmodify"=>"auto_ids", 
					"update"=>$update,
					"query"=>$query, 
					"new"=>true, "upsert"=>true
					);
			$ret = $this->db->command($command);
			$val = $ret["value"];
			return $val["$auto_increment"];
			} catch (Exception $e) {
				return 1;
			}
	}
	/**
	 * 获取自增id的方法2.通过最大值+1获取
	 * 注意 效率有问题，只能用于小数据表
	 * @param unknown_type $table_name
	 * @param unknown_type $field 
	 */	
	public function getMaxAutoId_mongodb($table_name,$field)
	{
		try {
			$result = $this->db->$table_name->find(array(),array($field))->sort(array($field=>-1))->limit(1);		
			foreach($result as $key=>$val){ 
				$ret[] = $val;
			};
			return intval($ret[0][$field]+1);
		} catch (Exception $e){
			return 1;
		}
	}	
	/**
	 * 插入记录
	 *
	 * @param string $collection		collection
	 * @param array  $fields_vals 		域名_值        	例：array("x" =>100,"y" => 20)
	 * @return array
	 */
	public function insert_mongodb($collection, $key_vals)
	{
		$collection = $this->db->$collection;
		$collection->insert($key_vals);
	}
	
	/**
	 * 修改记录
	 *
	 * @param string $collection	collection
	 * @param array $wheres 			条件        例：array("x" => array('$gt' => 80))
	 * @param array  $fields_vals 		域名_值        	例：array("x" =>100,"y" => 20)
	 * @param array $options 选项                   例：array(’safe’=>true,’multiple’=>true) 
	 * safe 是否返回操作结果
		fsync 是否是直接影响到物理硬盘
		upsert 是否没有匹配数据就添加一条新的
		multiple 是否影响所有符合条件的记录，默认只影响一条
	 * @return array
	 * 
     * Less than.							const LT = '$lt';
     * Less than or equal to.				const LTE = '$lte';
     * Greater than.						const GT = '$gt';
     * Greater than or equal to.    		const GTE = '$gte';
     * Checks for a field in an object.	    const IN = '$in';
     * Not equal.						    const NE = '$ne';
     * Sort ascending.					    const ASC = 1;
     * Sort descending.						const DESC = -1;
	 */
	public function update_mongodb($collection, $wheres, $fields_vals,$options=array()){
		$collection = $this->db->$collection;
		try {
			$collection->update($wheres, $fields_vals,$options); 
			return true;
			} catch (Exception $e) {
			return false;
			}			
	}	
	
	/**
	 * 删除记录
	 *
	 * @param string $collection	collection
	 * @param array $wheres 			条件        例：array("x" => array('$gt' => 80))
	 * @return array
	 * 
     * Less than.							const LT = '$lt';
     * Less than or equal to.				const LTE = '$lte';
     * Greater than.						const GT = '$gt';
     * Greater than or equal to.    		const GTE = '$gte';
     * Checks for a field in an object.	    const IN = '$in';
     * Not equal.						    const NE = '$ne';
     * Sort ascending.					    const ASC = 1;
     * Sort descending.						const DESC = -1;
	 */
	public function delete_mongodb($collection, $wheres){
		$collection = $this->db->$collection;
		try {
			$collection->remove($wheres); 
			return true;
			} catch (Exception $e) {
			return false;
			}			
	}	
	
	/**
	 * 统计记录数
	 *
	 * @param string $collection	collection
	 * @param array $wheres 			条件        例：array("x" => array('$gt' => 80))
	 * @return array
	 * 
     * Less than.							const LT = '$lt';
     * Less than or equal to.				const LTE = '$lte';
     * Greater than.						const GT = '$gt';
     * Greater than or equal to.    		const GTE = '$gte';
     * Checks for a field in an object.	    const IN = '$in';
     * Not equal.						    const NE = '$ne';
     * Sort ascending.					    const ASC = 1;
     * Sort descending.						const DESC = -1;
	 */
	public function count_mongodb($collection, $wheres){
		$collection = $this->db->$collection;
		try {
			return $collection->count((object)$wheres); 
		} catch (Exception $e) {
			return 0;
		}			
	}	
	
	/**
	 * 分页
	 *
	 * @param string $collection	collection
	 * @param int $curpage			当前页号
	 * @param int $pagesize			页长
	 * @param array $wheres 		条件        例：array("x" => array('$gt' => 80))
	 * @param array $fields 		指定域(null为所有)
	 * @param array $orderby		排序
	 * @param string $url           分页url
	 * @return array
	 * 
     * Less than.							const LT = '$lt';
     * Less than or equal to.				const LTE = '$lte';
     * Greater than.						const GT = '$gt';
     * Greater than or equal to.    		const GTE = '$gte';
     * Checks for a field in an object.	    const IN = '$in';
     * Not equal.						    const NE = '$ne';
     * 
     * Sort ascending.					    const ASC = 1;
     * Sort descending.						const DESC = -1;
	 */
	public function findpage_mongodb($collection, $curpage, $pagesize, $wheres, $fields, $orderby, $url, $returnId=false){
		$pages = array();	
		//总记录数量	
		$totalnumber = $this->count_mongodb($collection, $wheres);
		//总页面数量
    	$totalpage = ceil($totalnumber/$pagesize);
    	$totalpage = $totalpage ? ($totalpage) : (1);
       //修改当前页面
    	if ($curpage < 1)
    	{
        	$curpage = 1;
    	}
   		 else if ($curpage > $totalpage)
    	{
        	$curpage = $totalpage;
    	} 			
		$pages["curpage"] = $curpage;
		
		$pages["totalpage"] = $totalpage;
		$pages["totalnumber"] = $totalnumber;
		$pages["url"] = $url;		
	
		$collection = $this->db->$collection;
		
		if ($wheres == null) $wheres_1 = array();
		else $wheres_1 = $wheres;
			
		if ($fields == null) $fields_1 = array();
		else $fields_1 = $fields;
        if(!$returnId)
		    $fields_1["_id"] = 0;
		
		$data = array();
		try {
			if ($orderby == null)
				$result = $collection->find($wheres_1, $fields_1)->skip(($curpage-1)*$pagesize)->limit($pagesize); 
			else
				$result = $collection->find($wheres_1, $fields_1)->sort((object)$orderby)->skip(($curpage-1)*$pagesize)->limit($pagesize); 
			foreach($result as $val){ $data[] = $val;};
			} catch (Exception $e) {
			}	
		$pages["data"] = $data;			
		return $pages;
	}
	
	//返回mongodb实例
	public function getDB_mongodb(){
		if ( $this->config['db'] == 'mongodb' ) 
		{
			return $this->db;
		}
		else
		{
			return null;
		}
	}
}
